package org.duang.kit;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.duang.db.IdEntity;
import org.duang.db.annotation.Index;
import org.duang.db.annotation.Vo;
import org.duang.db.annotation.VoColl;
import org.duang.db.sql.DBSession;
import org.duang.db.sql.SqlDao;
import org.duang.db.sql.parser.SqlDecodeConvetor;
import org.duang.vtor.annotation.Vtor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SqlKit {

	private final static Logger logger = LoggerFactory.getLogger(SqlKit.class);
	private static Set<String> allTables = new HashSet<String>();
	private static ConcurrentMap<String, SqlDao<?>> daoCache = new ConcurrentHashMap<String, SqlDao<?>>();
	private static final String SQL_ID_FIELD = "id";
	private static final Object[] NULL_OBJECT = new Object[0];
	
	// 取出数据库所有表,加载到Map
	public static void getAllTable() throws Exception {
		List<String> list = DBSession.getMysqlTables();
		if(ToolsKit.isNotEmpty(list)){
			allTables.addAll(list);
		}
	}

	@SuppressWarnings("unchecked")
	public static <T> SqlDao<T> get(Class<T> cls) {
		String key = ClassKit.getClassName(cls);
		SqlDao<?> dao = daoCache.get(key);
		if (null == dao) {
			dao = new SqlDao<T>(cls);
			daoCache.put(key, dao);
		}
		return (SqlDao<T>) dao;
	}

	/**
	 * 是否存在表
	 * 
	 * @param cls
	 *            Entiey类
	 * @return 存在返回true, 否则反之
	 */
	public static boolean isExist(Class<?> cls) throws Exception {
		String beanName = ClassKit.getBeanName(cls, true);
		boolean isExist = false;
		if(ToolsKit.isEmpty(allTables) && !allTables.contains(beanName)){
			logger.info("get "+ beanName +" table is null!" );
		} else {
			for(Iterator<String > it= allTables.iterator(); it.hasNext();) {
				String tableName = it.next();
				if(tableName.equalsIgnoreCase(beanName)) {
					isExist = true;
					break;
				}
			}
		}
		return isExist;
	}

	/**
	 * 初始化表
	 * 
	 * @param cls
	 *            Entiey类
	 */
	public static void createTable(Class<?> cls) throws Exception {
		if(!isExist(cls)){	//不存在时创建新的表
			String tableName = ClassKit.getBeanName(cls,true);
			Field[] fields = ClassKit.getFields(cls);
			StringBuilder columnString = new StringBuilder();
			columnString.append(IdEntity.ID_FIELD).append(" varchar(50) primary key,");			
			for(Field field : fields) {
				String name = field.getName();
				if(name.equals(SQL_ID_FIELD) || field.isAnnotationPresent(Vo.class) || field.isAnnotationPresent(VoColl.class)) continue;
				Class<?> typeClass = field.getType();
				String sqlType = conversion2SqlType(typeClass, field);
				if(ToolsKit.isEmpty(sqlType)) continue;
				columnString.append(name).append(" ").append(sqlType).append(",");
			}
			if(columnString.length() > 0) columnString.deleteCharAt(columnString.length()-1);
			if(columnString.length() == 0){
				logger.info("create table sql is empty, exit...");
				return;
			}
			StringBuilder createTabelSql = new StringBuilder("create table ");
			createTabelSql.append(tableName).append(" (").append(columnString).append(")");
			createTabelSql.append(" engine=InnoDB default charset=utf8 collate=utf8_general_ci;");
			int row = DBSession.execute(createTabelSql.toString(), NULL_OBJECT);
			if(row >= 0){
				allTables.add(tableName);
				logger.info( "create " + tableName +" table success... ");
			}
		}
	}

	public static List<String> getIndexs(Class<?> cls) {
		String tableName = ClassKit.getBeanName(cls, true);
		List<String> indexList = DBSession.getIndexs(tableName);
		return ToolsKit.isEmpty(indexList) ? null : indexList;
	}
	
	/**
	 * 创建表索引
	 * @param tableName		表名
	 */
	public static void createIndex(Class<?> cls) throws Exception{
		if(isExist(cls)){
			String tableName = ClassKit.getBeanName(cls, true);
			// 先去查表里已经存在的索引
			List<String> indexs = getIndexs(cls);
			Field[] fields = ClassKit.getFields(cls);
			StringBuilder indexSql = new StringBuilder();
			for(Field field : fields){
				Index index = field.getAnnotation(Index.class);
				String columnName = field.getName();
				if(ToolsKit.isNotEmpty(index)){
					indexSql.delete(0,indexSql.length());
					String indexName = ToolsKit.isEmpty(index.name()) ? "_"+columnName+"_" : index.name();
					indexName = indexName.toLowerCase();
					if(ToolsKit.isNotEmpty(indexs) && !indexs.contains(indexName)){	//如果不存在则添加，存在则不作任何处理
						boolean unique = index.unique();
//						String type = ToolsKit.isEmpty(index.type()) ? "normal" : "text".equalsIgnoreCase(index.type()) ? "normal" : index.type();
						String order = ToolsKit.isEmpty(index.order()) ? "asc" : index.order();
						indexSql.append("create ");
						if(unique) indexSql.append("unique "); //else indexSql.append(type);					
						indexSql.append(" index ").append(indexName).append(" on ").append(tableName).append("(").append(columnName);
						if("DESC".equalsIgnoreCase(order)){
							indexSql.append(" ").append(order);
						}					
						indexSql.append(")");
						DBSession.execute(indexSql.toString(), NULL_OBJECT);
					} 
				}
			}
		}
	}

	private static String conversion2SqlType(Class<?> type, Field field){
		String sqlType = "";
		Vtor vtor = field.getAnnotation(Vtor.class);
		int len = 0;
		if(null != vtor) {	len = vtor.length();}
		if(DataType.isString(type)){
			sqlType = "varchar("+ ((len>0) ? len : 50) +")";
		} else if(DataType.isInteger(type) || DataType.isIntegerObject(type)) {
			sqlType = "int("+ ((len>0) ? len : 7) +")";
		} else if(DataType.isLong(type) || DataType.isLongObject(type)) {
			sqlType = "bigint("+ ((len>0) ? len : 11) +")";
		}  else if(DataType.isDate(type)) {
			sqlType = "datetime";
		} 
		return sqlType.toLowerCase().trim();
	}
	
	@SuppressWarnings("unchecked")
	public static <T> T toList(List<Map<String,Object>> queryList) {
		if(ToolsKit.isEmpty(queryList)) return null;
		List<T>resultList = new ArrayList<T>(queryList.size());
		for(Iterator<Map<String,Object>> it = queryList.iterator(); it.hasNext();){
			Map<String,Object> map = it.next();
			if(ToolsKit.isEmpty(map)) continue;
			for(Iterator<Entry<String,Object>>mapIt = map.entrySet().iterator(); mapIt.hasNext();){
				Entry<String,Object> entry = mapIt.next();
				if(ToolsKit.isNotEmpty(entry)){
					resultList.add((T)entry.getValue());
				}
			}
		}
		return (T)resultList;
	}
	
	
	public static <T> T toBean(Class<T> cls, Map<String,Object> result){
		return SqlDecodeConvetor.convetor(cls, result);
	}
	
	public static <T> List<T> toBeans(Class<T> cls, List<Map<String,Object>> results){
		List<T> voList = new ArrayList<T>(results.size());
		for(Iterator<Map<String,Object>> it = results.iterator(); it.hasNext();){
			Map<String,Object> map = it.next();
			voList.add(SqlDecodeConvetor.convetor(cls, map));
		}
		return voList;
	}
	
}
